/**
 * This jQuery plugin displays pagination links inside the selected elements. This plugin needs at least jQuery 1.4.2
 * 
 * @author Gabriel Birke (birke *at* d-scribe *dot* de)
 * @version 2.2
 * @param {int} maxentries Number of entries to paginate
 * @param {Object} opts Several options (see README for documentation)
 * @return {Object} jQuery Object
 */
(function($) {
	/**
	 * @class Class for calculating pagination values
	 */
	$.PaginationCalculator = function(maxentries, opts) {// 页面计算器
		this.maxentries = maxentries;// 总记录数
		this.opts = opts;// 选项
	}

	$.extend($.PaginationCalculator.prototype, {// 绑定 页面计算器 里的方法
		/**
		 * Calculate the maximum number of pages
		 * 
		 * @method
		 * @returns {Number}
		 */
		numPages : function() {// 取计算出的页数 取大于计算值的整数部分
			return Math.ceil(this.maxentries / this.opts.items_per_page);// 计算总页数
		},
		/**
		 * Calculate start and end point of pagination links depending on current_page and num_display_entries.
		 * 
		 * @returns {Array}
		 */
		getInterval : function(current_page) {// 计算开始和结束区间
			var ne_half = Math.floor(this.opts.num_display_entries / 2);// 要显示出来的总页数 的一半 5
			var np = this.numPages();// 总页数 11
			var upper_limit = np - this.opts.num_display_entries;// 最大数量的分页链接,是可见的。设置为0来显示 简单的“前/下一步”导航。默认值:10
			var start = current_page > ne_half ? Math.max(Math.min(current_page - ne_half, upper_limit), 0) : 0;
			var end = current_page > ne_half ? Math.min(current_page + ne_half + (this.opts.num_display_entries % 2),
					np) : Math.min(this.opts.num_display_entries, np);
			return {
				start : start,
				end : end
			};
		}
	});

	// Initialize jQuery object container for pagination renderers
	$.PaginationRenderers = {};// 分页实施器

	// ------------------------------------默认[横向]的页面内容生成器 开始-----------------------------------------
	/**
	 * @class Default renderer for rendering pagination links
	 */
	$.PaginationRenderers.defaultRenderer = function(maxentries, opts) {
		this.maxentries = maxentries;
		this.opts = opts;
		this.pc = new $.PaginationCalculator(maxentries, opts);
	}
	$.extend($.PaginationRenderers.defaultRenderer.prototype, {
		/**
		 * Helper function for generating a single link (or a span tag if it's the current page)
		 * 
		 * @param {Number} page_id The page id for the new item
		 * @param {Number} current_page
		 * @param {Object} appendopts Options for the new item: text and classes
		 * @returns {jQuery} jQuery object containing the link
		 */
		createLink : function(page_id, current_page, appendopts) {
			var lnk, np = this.pc.numPages();
			page_id = page_id < 0 ? 0 : (page_id < np ? page_id : np - 1); // Normalize page id to sane value
			appendopts = $.extend({
				text : page_id + 1,
				classes : ""
			}, appendopts || {});
			if (page_id == current_page) {
				lnk = $("<span class='current'>" + appendopts.text + "</span>");
			} else {
				lnk = $("<a>" + appendopts.text + "</a>").attr('href', this.opts.link_to.replace(/__id__/, page_id));
			}
			if (appendopts.classes) {
				lnk.addClass(appendopts.classes);
			}
			lnk.data('page_id', page_id);
			return lnk;
		},
		// Generate a range of numeric links container:容器
		appendRange : function(container, current_page, start, end, opts) {
			var i;
			for (i = start; i < end; i++) {
				this.createLink(i, current_page, opts).appendTo(container);
			}
		},
		getLinks : function(current_page, eventHandler) {
			var begin, end, interval = this.pc.getInterval(current_page), // 页码区间
			np = this.pc.numPages(), // 总页数
			fragment = $("<div class='pagination'></div>");// 容器html代码段

			// Generate "Previous"-Link
			if (this.opts.prev_text && (current_page > 0 || this.opts.prev_show_always)) {
				fragment.append(this.createLink(current_page - 1, current_page, {
					text : this.opts.prev_text,
					classes : "prev"
				}));
			}
			// Generate starting points
			if (interval.start > 0 && this.opts.num_edge_entries > 0) {
				end = Math.min(this.opts.num_edge_entries, interval.start);
				this.appendRange(fragment, current_page, 0, end, {
					classes : 'sp'
				});
				if (this.opts.num_edge_entries < interval.start && this.opts.ellipse_text) {
					jQuery("<span>" + this.opts.ellipse_text + "</span>").appendTo(fragment);
				}
			}
			// Generate interval links
			this.appendRange(fragment, current_page, interval.start, interval.end);
			// Generate ending points
			if (interval.end < np && this.opts.num_edge_entries > 0) {
				if (np - this.opts.num_edge_entries > interval.end && this.opts.ellipse_text) {
					jQuery("<span>" + this.opts.ellipse_text + "</span>").appendTo(fragment);
				}
				begin = Math.max(np - this.opts.num_edge_entries, interval.end);
				this.appendRange(fragment, current_page, begin, np, {
					classes : 'ep'
				});

			}
			// Generate "Next"-Link
			if (this.opts.next_text && (current_page < np - 1 || this.opts.next_show_always)) {
				fragment.append(this.createLink(current_page + 1, current_page, {
					text : this.opts.next_text,
					classes : "next"
				}));
			}
			$('a', fragment).click(eventHandler);
			return fragment;
		}
	});
	// ------------------------------------默认[横向]的页面内容生成器 结束-----------------------------------------
	
	//李广彬  2013-06-23 12:04 扩展
	// ------------------------------------默认[坚向]的页面内容生成器 开始-----------------------------------------
	/**
	 * @class Default renderer for rendering pagination links
	 */
	$.PaginationRenderers.verticalRenderer = function(maxentries, opts) {
		this.maxentries = maxentries;
		this.opts = opts;
		this.pc = new $.PaginationCalculator(maxentries, opts);
	}
	$.extend($.PaginationRenderers.verticalRenderer.prototype, {
		/**
		 * 生成单个连接项
		 * 
		 * @param {Number} page_id 页码
		 * @param {Number} current_page 当前页码
		 * @param {Object} appendopts 对像对应选项: text and classes
		 * @returns jquery 对像
		 */
		createLink : function(page_id, current_page, appendopts) {
			var lnk, np = this.pc.numPages(), showTitle;
			page_id = page_id < 0 ? 0 : (page_id < np ? page_id : np - 1); // Normalize page id to sane value
			appendopts = $.extend({
				text : page_id + 1,
				classes : ""
			}, appendopts || {});
			showTitle = appendopts.text;
			showTitle = appendopts.title_prefix_text ? appendopts.title_prefix_text + showTitle : showTitle;
			showTitle = appendopts.title_suffix_text ? showTitle + appendopts.title_suffix_text : showTitle;
			if (page_id == current_page) {
				lnk = $("<span class='current'>" + showTitle + "</span>");
			} else {
				lnk = $("<a>" + showTitle + "</a>").attr('href', this.opts.link_to.replace(/__id__/, page_id));
			}
			if (appendopts.classes) {
				lnk.addClass(appendopts.classes);
			}
			lnk.data('page_id', page_id);
			return lnk;
		},
		/**
		 * 坚向里的每一个li项
		 * @param page_id 页码
		 * @param current_page 当前页码
		 * @param appendopts 选项
		 * @returns
		 */
		createItem : function(page_id, current_page, appendopts) {// 创建item条目
			var item = $("<li></li>");
			this.createLink(page_id, current_page, appendopts).prependTo(item);
			return item;
		},
		/**
		 * 生成指定范围的页码项
		 * @param container 容器
		 * @param current_page 当前页
		 * @param start 开始页码
		 * @param end 结束页码
		 * @param opts 选项：显示的文本、对应的class
		 */
		appendRange : function(container, current_page, start, end, opts) {
			var i;
			for (i = start; i < end; i++) {
				this.createItem(i, current_page, opts).prependTo(container);
			}
		},
		/**
		 * 生成所有的页码项
		 * @param current_page 当前页
		 * @param eventHandler 事件绑定
		 * @returns
		 */
		getLinks : function(current_page, eventHandler) {
			var begin, end, interval = this.pc.getInterval(current_page), // 页码区间
			np = this.pc.numPages(), // 总页数
			fragment = $("<div class='pagination'></div>"), // 容器html代码段
			items = $("<ul style='display:none'></ul>");// 所有的分页条目

			// 生成上一页 标签
			if (this.opts.prev_text && (current_page > 0 || this.opts.prev_show_always)) {
				fragment.append(this.createLink(current_page - 1, current_page, {
					text : this.opts.prev_text,
					classes : "prev"
				}));
			}
			// 生成开始点 固定个数页面项
			if (interval.start > 0 && this.opts.num_edge_entries > 0) {
				end = Math.min(this.opts.num_edge_entries, interval.start);
				this.appendRange(items, current_page, 0, end, jQuery.extend({
					classes : 'sp'
				}, this.opts || {}));
				if (this.opts.num_edge_entries < interval.start && this.opts.ellipse_text) {
					jQuery("<li><span>" + this.opts.ellipse_text + "</span></li>").prependTo(items);
				}
			}
			// 生成指定个数连续的页码项
			this.appendRange(items, current_page, interval.start, interval.end, this.opts);
			// Generate ending points
			if (interval.end < np && this.opts.num_edge_entries > 0) {
				if (np - this.opts.num_edge_entries > interval.end && this.opts.ellipse_text) {
					jQuery("<li><span>" + this.opts.ellipse_text + "</span></li>").prependTo(items);
				}
				begin = Math.max(np - this.opts.num_edge_entries, interval.end);
				this.appendRange(items, current_page, begin, np, jQuery.extend({
					classes : 'ep'
				}, this.opts || {}));

			}
			//生成每次选中的页码项
			fragment.append(this.createLink(current_page, current_page, jQuery.extend({
				text : current_page + 1,
				classes : "currentShow"
			}, this.opts || {})).prepend(items));
			//生成下一页标签
			if (this.opts.next_text && (current_page < np - 1 || this.opts.next_show_always)) {
				fragment.append(this.createLink(current_page + 1, current_page, {
					text : this.opts.next_text,
					classes : "next"
				}));
			}
			//私有方法： 以指定元素为基准计算列表项ul相对父对像的相对漂移位置
			function positioningUl(UlObj,middleObj){
				var ulWidth = UlObj.width();
				var width = $(middleObj).width();
				var left = $(middleObj).position().left;
				var paddingLeft = parseInt($(middleObj).css("padding-left"));
				var floatingWidth = (ulWidth - width) / 2;
				var ulLeft = left + paddingLeft - floatingWidth;
				UlObj.css("left", ulLeft);
				return ulLeft;
			}
			$('a', fragment).click(eventHandler);
			//当前页显示事件绑定
			$('.currentShow', fragment).click(function() {
				UlObj.toggle();
			}).hover(function() {
				positioningUl($("ul", fragment),this);
				$("ul", fragment).show();
			}, function() {
				positioningUl($("ul", fragment),this);
				$("ul", fragment).hide();
			});
			return fragment;
		}
		
	});
	// ------------------------------------默认[坚向]的页面内容生成器 结束-----------------------------------------

	// Extend jQuery
	$.fn.pagination = function(maxentries, opts) {

		// Initialize options with default values
		opts = jQuery.extend({
			items_per_page : 10,
			num_display_entries : 11,
			current_page : 0,
			num_edge_entries : 0,
			link_to : "#",
			prev_text : "Prev",
			next_text : "Next",
			title_prefix_text : "第 ",
			title_suffix_text : " 页",
			ellipse_text : "...",
			prev_show_always : true,
			next_show_always : true,
			renderer : "defaultRenderer",//defaultRenderer  verticalRenderer
			load_first_page : false,
			callback : function() {
				return false;
			}
		}, opts || {});

		// 容器；集装箱
		var containers = this, renderer, links, current_page;

		/**
		 * This is the event handling function for the pagination links.
		 * 
		 * @param {int} page_id The new page number
		 */
		function paginationClickHandler(evt) {
			var links, new_current_page = $(evt.target).data('page_id'), continuePropagation = selectPage(new_current_page);
			if (!continuePropagation) {
				evt.stopPropagation();
			}
			return continuePropagation;
		}

		/**
		 * This is a utility function for the internal event handlers. It sets the new current page on the pagination
		 * container objects, generates a new HTMl fragment for the pagination links and calls the callback function.
		 */
		function selectPage(new_current_page) {
			// update the link display of a all containers
			containers.data('current_page', new_current_page);
			links = renderer.getLinks(new_current_page, paginationClickHandler);
			containers.empty();
			links.appendTo(containers);
			// call the callback and propagate the event if it does not return false
			var continuePropagation = opts.callback(new_current_page, containers);
			return continuePropagation;
		}

		// -----------------------------------
		// Initialize containers
		// -----------------------------------
		current_page = opts.current_page;
		containers.data('current_page', current_page);
		// Create a sane value for maxentries and items_per_page
		maxentries = (!maxentries || maxentries < 0) ? 1 : maxentries;
		opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0) ? 1 : opts.items_per_page;

		if (!$.PaginationRenderers[opts.renderer]) {
			throw new ReferenceError("Pagination renderer '" + opts.renderer
					+ "' was not found in jQuery.PaginationRenderers object.");
		}
		renderer = new $.PaginationRenderers[opts.renderer](maxentries, opts);

		// Attach control events to the DOM elements
		var pc = new $.PaginationCalculator(maxentries, opts);
		var np = pc.numPages();
		containers.bind('setPage', {
			numPages : np
		}, function(evt, page_id) {
			if (page_id >= 0 && page_id < evt.data.numPages) {
				selectPage(page_id);
				return false;
			}
		});
		containers.bind('prevPage', function(evt) {
			var current_page = $(this).data('current_page');
			if (current_page > 0) {
				selectPage(current_page - 1);
			}
			return false;
		});
		containers.bind('nextPage', {
			numPages : np
		}, function(evt) {
			var current_page = $(this).data('current_page');
			if (current_page < evt.data.numPages - 1) {
				selectPage(current_page + 1);
			}
			return false;
		});

		// When all initialisation is done, draw the links
		links = renderer.getLinks(current_page, paginationClickHandler);
		containers.empty();
		links.appendTo(containers);
		// call callback function
		if (opts.load_first_page) {
			opts.callback(current_page, containers);
		}
	} // End of $.fn.pagination block

})(jQuery);
